package photo;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;

import utils.Logger;

import Luxand.FSDK;
import Luxand.FSDK.FSDK_Features;
import Luxand.FSDK.HImage;
import Luxand.FSDK.TPoint;

public class Photo {

	public static final String license_key = "LOGFU3/g0YsI73DfnuHmdAbFf1aylY8MTDd/QfLbcK+r5p2TI84/FsXu2jkEnAniV/roHx3vkOHfyBU5bzfJmWl/yTk8U0WopnaSXyKJp0yeImpH/0ipgPvE86QjH7mLDWF/TsjwwofzyGTm0g2ZPuEMZ7RCq1LXJLnNRE9eQqQ=";

	private String filePath;
	private FSDK.TPoint[] features = null;

	private static boolean initialized = false;

	static {
		if (!initialized) {
			if (FSDK.ActivateLibrary(license_key) != FSDK.FSDKE_OK)
				try {
					throw new Exception();
				} catch (Exception e) {
					e.printStackTrace();
				}
			FSDK.Initialize();
			FSDK.SetFaceDetectionParameters(false, true, 384);
			initialized = true;
		}
	}

	// API

	/*
	 * Creates a Photo instance by image file path.
	 */
	public Photo(String filePath) throws Exception {
		this.filePath = filePath;
	}

	/*
	 * Creates a new image file next to the original with visualized facial
	 * features.
	 */
	public void generateFeatures() throws Exception {
		this.createFeatures(false, false);
	}

	/*
	 * Creates a new image file next to the original with visualized facial
	 * features.
	 */
	public void visualizeFeatures() throws Exception {
		this.createFeatures(true, false);
	}

	// public createVecotorData(String filePath, );

	public String featuresToString() throws Exception {
		String str = "";
		for (int i = 0; i < this.features.length; i++) {
			str += "[" + String.valueOf(this.features[i].x) + ","
					+ String.valueOf(this.features[i].y) + "]";
			if (i < this.features.length - 1)
				str += ";";
			else
				str += ":";
		}
		if (str.split(":")[0].split(";").length != 66)
			throw new Exception(this.filePath + ": missing feature points");
		return str;
	}

	// private

	private void createFeatures(boolean visualize,
			boolean createDataFile) throws Exception {
		HImage imageHandle = new HImage();

		if (FSDK.LoadImageFromFileW(imageHandle, this.filePath) == FSDK.FSDKE_OK) {

			FSDK.TFacePosition.ByReference facePosition = new FSDK.TFacePosition.ByReference();
			if (FSDK.DetectFace(imageHandle, facePosition) == FSDK.FSDKE_OK) {

				FSDK_Features.ByReference vFacialFeatures = new FSDK_Features.ByReference();
				if (visualize) {
					if (FSDK.DetectFacialFeaturesInRegion(imageHandle,
							facePosition, vFacialFeatures) != FSDK.FSDKE_OK)
						throw new Exception();
				}

				HImage destImg = new HImage();
				FSDK.CreateEmptyImage(destImg);
				FSDK.RotateImage(imageHandle, facePosition.angle, destImg);

				imageHandle = destImg;
				if (FSDK.DetectFace(imageHandle, facePosition) == FSDK.FSDKE_OK) {

					FSDK_Features.ByReference facialFeatures = new FSDK_Features.ByReference();

					if (FSDK.DetectFacialFeaturesInRegion(imageHandle,
							facePosition, facialFeatures) == FSDK.FSDKE_OK) {
						this.features = facialFeatures.features;

						if (visualize) {
							BufferedImage sourceImage = null;
							sourceImage = ImageIO.read(new File(this.filePath));
							TPoint p;
							int dotSize = 5;
							for (int i = 0; i < facialFeatures.features.length; i++) {
								p = facialFeatures.features[i];
								drawCircle(p.x, p.y, dotSize, 16720896, null,
										Color.BLUE.getRGB(), sourceImage);
							}
							File output = new File(filePath + ".png");
							ImageIO.write(sourceImage, "png", output);
						}

					} else {
						Logger.log("photo", "ERROR: Image " + this.filePath + " - no features detected!");
					}
				} else {
					Logger.log("photo", "ERROR: Image " + this.filePath + " - no face detected on rotated image!");
				}

			} else {
				Logger.log("photo", "ERROR: Image " + this.filePath + " - no face detected!");
			}

			FSDK.FreeImage(imageHandle);
		} else {
			Logger.log("photo", "ERROR: Image " + this.filePath + " cannote be loaded!");
		}
	}

	private static void drawCircle(int center_x, int center_y, int size,
			int color, String text, int textColor, BufferedImage img) {

		for (int i = (center_x - (size / 2)); i <= (center_x + (size / 2)); i++) {
			for (int j = (center_y - (size / 2)); j <= (center_y + (size / 2)); j++) {
				if (i <= img.getWidth() && j <= img.getHeight())
					try {
						img.setRGB(i, j, color);
					} catch (Exception e) {
					}
			}
		}
		if (text != null) {
			Font font = new Font("Arial", textColor, 18);
			Graphics g = img.getGraphics();
			g.setFont(font);
			g.setColor(Color.blue);
			g.setFont(font);
			if ((center_x - (size / 2)) <= img.getWidth()
					&& (center_y - (size / 2)) <= img.getHeight())
				g.drawString(text, (center_x - (size / 2)),
						(center_y - (size / 2)));
		}
	}

}
